home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / stdwin / Packs / vt / vt.c < prev    next >
Encoding:
Text File  |  1991-05-14  |  19.7 KB  |  651 lines  |  [TEXT/????]

  1. /* Virtual Terminal -- basic output routines */
  2.  
  3. #include "vtimpl.h"
  4.  
  5. #ifdef macintosh
  6. /* Bold mode uses the "Bold" font, found in VersaTerm;
  7.    this matches Monaco and is available only in 9 pt. */
  8. #define DO_BOLD
  9. #define SETBOLD() wsetfont("Bold")
  10. #define SETNORMAL() wsetfont("Monaco")
  11. #endif
  12.  
  13. /* Forward */
  14. STATIC void vtdrawproc _ARGS((WINDOW *win,
  15.                 int left, int top, int right, int bottom));
  16. STATIC void vtdraw _ARGS((VT *vt, int r1, int c1, int r2, int c2));
  17. STATIC void vtchrange _ARGS((VT *vt, int rr_top;
  18.             llen[row] = 0;
  19.         }
  20.         oldcol = col; /* For vtdraw call below */
  21.  
  22.         /* If the cursor is beyond the current line length,
  23.            eg because of cursor positioning, pad with space.
  24.            Set llen_row to the new line length. */
  25.         llen_row = llen[row];
  26.         if (llen_row < col) {
  27.             do {
  28.                 vt->data[row][llen_row] = ' ';
  29.                 vt->flags[row][llen_row] = 0;
  30.             } while (++llen_row < col);
  31.         }
  32.  
  33.         /* Set n to the number of characters that can be
  34.            inserted in the current line */
  35.         n = vt->cols - col;
  36.         CLIPMAX(n, len);
  37.  
  38.         /* When inserting, shift the rest of the line right.
  39.            The last characters may fall of the edge. */
  40.         if (vt->insert && llen_row > col && col+n < vt->cols) {
  41.             int k;
  42.             llen_row += n;
  43.             CLIPMAX(llen_row, vt->cols);
  44.             vtscroll(vt, row, col, row+1, llen_row, 0, n);
  45.             for (k = llen_row - n; --k >= col; ) {
  46.                 vt->data[row][k+n] = vt->data[row][k];
  47.                 vt->flags[row][k+n] = vt->flags[row][k];
  48.             }
  49.         }
  50.  
  51.         /* Copy the characters into the line data */
  52. #ifndef NDEBUG
  53.         if (col + n > vt->cols || row >= vt->rows) {
  54.             fprintf(stderr, "col=%d, n=%d, row=%d\n", col,n,row);
  55.             vtpanic("Bad index in vtputstring");
  56.         }
  57. #endif
  58.         strncpy(vt->data[row] + col, text, n);
  59.  
  60.         /* Update loop administration, maintaining the invariant:
  61.            'len' characters starting at 'text' still to do */
  62.         len -= n;
  63.         text += n;
  64.  
  65.         /* Set the corresponding flag bits.
  66.            The current column is set as a side effect. */
  67.         while (--n >= 0)
  68.             vt->flags[row][col++] = vt->gflags;
  69.  
  70.         /* Update line length */
  71.         CLIPMIN(llen_row, col);
  72.         llen[row] = llen_row;
  73.  
  74.         /* Maybe draw the characters now */
  75.         if (vt->lazy) {
  76.             D( printf("vtputstring: ") );
  77.             vtchrange(vt, row, oldcol, row, col);
  78.         }
  79.         else if (wrap == 0) {
  80.             VTBEGINDRAWING(vt);
  81.             werase(oldcol*vt->cwidth, row*vt->cheight,
  82.                 col*vt->cwidth, (row+1)*vt->cheight);
  83.  
  84.             D( printf("vtputstring: ") );
  85.             last_drawn_col = col;
  86.             vtdraw(vt, row, oldcol, row + 1, col);
  87.         }
  88.  
  89.         /* Loop while more work to do */
  90.  
  91.     } while (len > 0);
  92.  
  93. #if 0
  94.     /* XXX Why not? */
  95.     vtsetcursor(vt, row, col);
  96. #endif
  97.  
  98.     /* Process delayed scrolling. */
  99.  
  100.     if (wrap > 0) {
  101.         /* Yes, we need to scroll.
  102.            When wrap > 1, we have scrolled more than a screenful;
  103.            then the vtscroll call is skipped, but we must still
  104.            circulate the lines internally. */
  105.  
  106.         /* Picture:
  107.  
  108.            scr_top ___________________ (first line affected)
  109.               .    ___________________
  110.               .    ______ row ________
  111.               .    ___________________ (last line affected)
  112.            scr_bot
  113.  
  114.            Data move: circulate down so that the data at row
  115.            moves to scr_bot - 1.
  116.            Screen bits move: the line below row must
  117.            become scr_top.
  118.            We must also invalidate the characters changed
  119.            before we started scrolling, but we must do this
  120.            after the vtscroll call, because some STDWIN
  121.            versions don't properly scroll invalidated bits.
  122.         */
  123.  
  124.         if (row + 1 != scr_bot) vtcirculate(vt,
  125.                     scr_top, scr_bot,
  126.                     scr_bot - (row + 1));
  127.         if (wrap == 1) {
  128.             int n = (row + 1) - scr_top;
  129.             D( printf("Wrapped once; n=%d\n", n) );
  130.             vtscroll(vt, scr_top, 0, scr_bot, vt->cols, -n, 0);
  131.             if (!vt->lazy)
  132.                 vtdraw(vt, scr_bot - n, last_drawn_col,
  133.                     scr_bot, vt->cols);
  134.         }
  135.         else { /* Scrolled more than the scrolling region */
  136.             D( printf("Whole scrolling region: ") );
  137.             if (!vt->lazy)
  138.                 vtdraw(vt, scr_top, 0, scr_bot, vt->cols);
  139.         }
  140.         row = scr_bot - 1;
  141.     }
  142.  
  143.     /* Set the new cursor position */
  144.     vtsetcursor(vt, row, col);
  145. }
  146.  
  147. /* Subroutine to invalidate the text range from (r1, c1) to (r2, c2).
  148.    This is not the same as vtchange; this function deals with text
  149.    ranges, while vtchange deals with rectangles. */
  150.  
  151. STATIC void
  152. vtchrange(vt, r1, c1, r2, c2)
  153.     VT *vt;
  154. {
  155.     D( printf("vtchrange [%d,%d]~[%d,%d]\n", c1, r1, c2, r2) );
  156.     if (c1 >= vt->cols) {
  157.         MON_EVENT("vtchrange: c1 >= vt->cols");
  158.         ++r1; c1 = 0;
  159.     }
  160.     if (r1 >= r2) {
  161.         vtchange(vt, r1, c1, r2+1, c2);
  162.     }
  163.     else {
  164.         vtchange(vt, r1, c1, r1+1, vt->cols);
  165.         vtchange(vt, r1+1, 0, r2, vt->cols);
  166.         vtchange(vt, r2, 0, r2+1, c2);
  167.     }
  168. }
  169.  
  170. /* Set cursor position.
  171.    This sets the STDWIN text caret and calls wshow for the character
  172.    at the cursor.
  173.    The cursor position is clipped to the screen dimensions,
  174.    but it may sit on the right edge just beyond the last character. */
  175.  
  176. void
  177. vtsetcursor(vt, row, col)
  178.     VT *vt;
  179.     int row, col;
  180. {
  181.     CLIPMAX(row, vt->rows - 1);
  182.     CLIPMIN(row, 0);
  183.     CLIPMAX(col, vt->cols);
  184.     CLIPMIN(col, 0);
  185.     vt->cur_row = row;
  186.     vt->cur_col = col;
  187.     CLIPMAX(col, vt->cols - 1);
  188.     if (!vt->lazy) {
  189.         VTENDDRAWING(vt);
  190.         wsetcaret(vt->win, col * vt->cwidth, row * vt->cheight);
  191.         vtshow(vt, row, col, row + 1, col);
  192.     }
  193. }
  194.  
  195. /* Set scrolling region.  Lines in [top...bot) can scroll.
  196.    If the parameters are valid, set the region and move to (0, 0);
  197.    if there is an error, reset the region and don't move.
  198.    (NB: the move is to (0, 0), not to the top of the region!) */
  199.  
  200. void
  201. vtsetscroll(vt, top, bot)
  202.     VT *vt;
  203.     int top, bot;
  204. {
  205.     vtsync(vt);
  206.     if (top >= vt->topterm && top < bot && bot <= vt->rows) {
  207.         vt->scr_top = top;
  208.         vt->scr_bot = bot;
  209.         vtsetcursor(vt, vt->topterm, 0);
  210.         /* vtshow(vt, vt->topterm, 0, vt->rows, vt->cols); */
  211.     }
  212.     else {
  213.         vt->scr_top = vt->topterm;
  214.         vt->scr_bot = vt->rows;
  215.     }
  216.     vtshow(vt, vt->scr_top, 0, vt->scr_bot, vt->cols);
  217. }
  218.  
  219. /* Major reset */
  220.  
  221. void
  222. vtreset(vt)
  223.     VT *vt;
  224. {
  225.     int row;
  226.  
  227.     vtchange(vt, 0, 0, vt->rows, vt->cols);
  228.     vtshow(vt, vt->topterm, 0, vt->rows, vt->cols);
  229.  
  230.     for (row = 0; row < vt->rows; ++row)
  231.         vt->llen[row] = 0;
  232.  
  233.     vt->toscroll = 0;
  234.     vtsetflags(vt, 0);
  235.     vtsetinsert(vt, FALSE);
  236.     vtsetscroll(vt, 0, 0);
  237.     vtsetcursor(vt, vt->topterm, 0);
  238.     vt->sel_col1 = vt->sel_row1 = 0;
  239.     vt->sel_col2 = vt->sel_row2 = 0;
  240.     vt->save_row = vt->save_col = 0;
  241.     vt->keypadmode = FALSE;
  242.     vt->lazy = FALSE;
  243.     vt->mitmouse = FALSE;
  244.     vt->visualbell = FALSE;
  245.     vt->flagschanged = TRUE;
  246.     vt->action = NULL; /* This invalidates all other parsing fields */
  247. }
  248.  
  249. /* Draw procedure - this one is called because stdwin discovered an expose */
  250.  
  251. STATIC void
  252. vtdrawproc(win, left, top, right, bottom)
  253.     WINDOW *win;
  254.     int left, top, right, bottom;
  255. {
  256.     VT *vt = vtfind(win);
  257.  
  258. #ifndef NDEBUG
  259.     if (vt == NULL) vtpanic("vtdrawproc not for VT window");
  260.     if (vt->drawing) vtpanic("vtdrawproc while drawing");
  261. #endif
  262.  
  263.     vt->drawing = 1;    /* Stdwin did this implicitely */
  264.     {
  265.         int cw = vt->cwidth;
  266.         int ch = vt->cheight;
  267.         int col1 = left / cw;
  268.         int col2 = (right + cw - 1) / cw;
  269.         int row1 = top / ch;
  270.         int row2 = (bottom + ch - 1) / vt->cheight;
  271.  
  272.         D( printf("vtdrawproc: ") );
  273.         vtdraw(vt, row1, col1, row2, col2);
  274.     }
  275.     vt->drawing = 0;    /* Stdwin will do this implicitely */
  276. }
  277.  
  278. STATIC void
  279. set_textstyle(vt, flags)
  280.     VT *vt;
  281.     int flags;
  282. {
  283. #if 0
  284.     /* This isn't right, for various reasons.  And do we need it? */
  285.     static int previous_flags = -3;    /* Or anything < 0    */
  286.  
  287.     if (flags == previous_flags) return;
  288.     D( printf("Set_textstyle: 0x%x => 0x%x\n", previous_flags, flags) );
  289.     previous_flags = flags;
  290. #endif
  291.     wsetplain();
  292.     if (flags & VT_UNDERLINE) wsetunderline();
  293.     if (flags & VT_INVERSE) wsetinverse();
  294. #ifdef DO_BOLD
  295.     if (flags & VT_BOLD) SETBOLD();
  296.     else SETNORMAL();
  297. #endif
  298. }
  299.  
  300. /* Draw procedure - doesn't draw [row2, col2], or any other
  301.    char at row2, takes care of underlining, inverse video etc */
  302.  
  303. STATIC void
  304. vtdraw(vt, row1, col1, row2, col2)
  305.     VT *vt;
  306.     int row1, col1, row2, col2;
  307. {
  308.     int cw = vt->cwidth;
  309.     int ch = vt->cheight;
  310.     register unsigned char cur_flags;
  311.     int row;
  312.  
  313.     VTBEGINDRAWING(vt);
  314.     D( printf("vtdraw [%d,%d]~[%d,%d]\n", col1, row1, col2, row2) );
  315.  
  316.     CLIPMIN(col1, 0);
  317.     CLIPMAX(col2, vt->cols);
  318.     CLIPMIN(row1, 0);
  319.     CLIPMAX(row2, vt->rows);
  320.  
  321.     for (row = row1; row < row2; ++row) {
  322.     register int col;
  323.     char *data_row = vt->data[row] + col1;
  324.     register unsigned char *flags_row = vt->flags[row] + col1;
  325.     int h = col1*cw;
  326.     int v = row*ch;
  327.     int first = col1;
  328.     register int last = vt->llen[row];
  329.  
  330.     CLIPMAX(last, col2);    /* Don't draw more than asked for */
  331.  
  332.     /* Set flags */
  333.     cur_flags = flags_row[0];
  334.     set_textstyle(vt, cur_flags);
  335.  
  336.     /* Attempt to draw as much text as possible in one wdrawtext */
  337.     for (col = first; col < last; ++col) {
  338.         if (*flags_row++ != cur_flags) {
  339.         int n = col-first;
  340.         /* n cannot be < 0; ==0 means this
  341.            line has different flags */
  342.         if (n > 0) {
  343.             wdrawtext(h, v, data_row, n);
  344.             first = col;
  345.             data_row += n;
  346.             h += n*cw;
  347.         }
  348.  
  349.         cur_flags = flags_row[-1];    /* Set new flags */
  350.         set_textstyle(vt, cur_flags);
  351.         }
  352.     }
  353.     /* Draw leftover text on this line and perhaps some black spaces: */
  354.     if (col > first) wdrawtext(h, v, data_row, col-first);
  355.     }
  356. }
  357.  
  358. /* Find the VT corresponding to a WINDOW */
  359.  
  360. VT *
  361. vtfind(win)
  362.     WINDOW *win;
  363. {
  364.     int i;
  365.     for (i = 0; i < nvt; ++i) {
  366.         if (vtlist[i]->win == win)
  367.             return vtlist[i];
  368.     }
  369.     return NULL;
  370. }
  371.  
  372. /* Subroutine to circulate lines.
  373.    For i in r1 ... r2-1, move line i to position i+n (modulo r2-r1).
  374.  
  375.    For ABS(n)==1, we have a fast solution that always works.
  376.    For larger n, we have a slower solution allocating a temporary buffer;
  377.    if we can't, we repeat the fast solution ABS(n) times (really slow).
  378.  
  379.    We assume reasonable input:
  380.     0 <= r1 < r2 <= vt->rows,
  381.     0 < abs(n) < r2-r1.
  382. */
  383.  
  384. void
  385. vtcirculate(vt, r1, r2, n)
  386.     register VT *vt;
  387.     int r1, r2;
  388.     int n;
  389. {
  390.     if (n == -1) { /* Fast solution, move 1 up */
  391.         char *tdata = vt->data[r1];
  392.         unsigned char *tflags = vt->flags[r1];
  393.         short tllen = vt->llen[r1];
  394.         register int i;
  395.         MON_EVENT("circulate -1");
  396.         for (i = r1+1; i < r2; ++i) {
  397.             vt->data[i-1] = vt->data[i];
  398.             vt->flags[i-1] = vt->flags[i];
  399.             vt->llen[i-1] = vt->llen[i];
  400.         }
  401.         vt->data[i-1] = tdata;
  402.         vt->flags[i-1] = tflags;
  403.         vt->llen[i-1] = tllen;
  404.     }
  405.     else if (n == 1) { /* Fast solution, move 1 down */
  406.         char *tdata = vt->data[r2-1];
  407.         unsigned char *tflags = vt->flags[r2-1];
  408.         short tllen = vt->llen[r2-1];
  409.         register int i;
  410.         MON_EVENT("circulate 1");
  411.         for (i = r2-1; i > r1; --i) {
  412.             vt->data[i] = vt->data[i-1];
  413.             vt->flags[i] = vt->flags[i-1];
  414.             vt->llen[i] = vt->llen[i-1];
  415.         }
  416.         vt->data[i] = tdata;
  417.         vt->flags[i] = tflags;
  418.         vt->llen[i] = tllen;
  419.     }
  420.     else if (n != 0) {
  421.         if (!slowcirculate(vt, r1, r2, n)) {
  422.             /* Couldn't -- do ABS(n) times the fast case... */
  423.             int step;
  424.             if (n < 0) {
  425.                 n = -n;
  426.                 step = -1;
  427.             }
  428.             else step = 1;
  429.             while (--n >= 0)
  430.                 vtcirculate(vt, r1, r2, step);
  431.         }
  432.     }
  433. }
  434.  
  435. /* Slow version of the above; move lines r1..r2-1 n lines up */
  436.  
  437. STATIC bool
  438. slowcirculate(vt, r1, r2, n)
  439.     register VT *vt;
  440.     int r1, r2;
  441.     int n; /* May be negative */
  442. {
  443.     char **tdata; /* Data buffer */
  444.     unsigned char **tflags; /* Flags buffer */
  445.     short *tllen; /* Line length buffer */
  446.     bool ok;
  447.  
  448.     if (n < 0) n += (r2 - r1);
  449.     tdata = NALLOC(char *, n);
  450.     tflags = NALLOC(unsigned char *, n);
  451.     tllen = NALLOC(short, n);
  452.  
  453.     MON_EVENT("slowcirculate");
  454.     /* Did all the malloc's work? */
  455.     ok = tdata != NULL && tflags != NULL && tllen != NULL;
  456.     if (ok) {
  457.         register int i;
  458.         r2 -= n; /* Now r2 "points" beyond the last target line */
  459.         /* Save data, flags and lengths to be overwritten */
  460.         for (i = 0; i < n; ++i) {
  461.             tdata[i] = vt->data[r2+i];
  462.             tflags[i] = vt->flags[r2+i];
  463.             tllen[i] = vt->llen[r2+i];
  464.         }
  465.         /* Copy "lower" part of the lines to r1..r1+n-1 (=r2-1) */
  466.         for (i = r2; --i >= r1; ) {
  467.             vt->data[i+n] = vt->data[i];
  468.             vt->flags[i+n] = vt->flags[i];
  469.             vt->llen[i+n] = vt->llen[i];
  470.         }
  471.         /* Restore saved lines in r1..r1+n-1 */
  472.         for (i = 0; i < n; ++i) {
  473.             vt->data[r1+i] = tdata[i];
  474.             vt->flags[r1+i] = tflags[i];
  475.             vt->llen[r1+i] = tllen[i];
  476.         }
  477.     }
  478.  
  479.     FREE(tdata);
  480.     FREE(tflags);
  481.     FREE(tllen);
  482.  
  483.     return ok;
  484. }
  485.  
  486. /* VT interface to wchange */
  487.  
  488. void
  489. vtchange(vt, r1, c1, r2, c2)
  490.     VT *vt;
  491.     int r1, c1, r2, c2;
  492. {
  493.     VTENDDRAWING(vt);
  494.     D( printf("vtchange [%d, %d]~[%d, %d]\n", c1, r1, c2, r2) );
  495.     wchange(vt->win,
  496.         c1 * vt->cwidth, r1 * vt->cheight,
  497.         c2 * vt->cwidth, r2 * vt->cheight);
  498. }
  499.  
  500. /* VT interface to wshow */
  501.  
  502. void
  503. vtshow(vt, r1, c1, r2, c2)
  504.     VT *vt;
  505.     int r1, c1, r2, c2;
  506. {
  507.     VTENDDRAWING(vt);
  508.     wshow(vt->win,
  509.         c1 * vt->cwidth, r1 * vt->cheight,
  510.         c2 * vt->cwidth, r2 * vt->cheight);
  511. }
  512.  
  513. /* VT interface to wscroll.
  514.    In lazy mode, the actual scrolling may be postponed
  515.    (by setting vt->toscroll). */
  516.  
  517. void
  518. vtscroll(vt, r1, c1, r2, c2, drow, dcol)
  519.     VT *vt;
  520.     int r1, c1, r2, c2;
  521.     int drow, dcol; /* Translation vector */
  522. {
  523.     int scr_top = vt->scr_top;
  524.     if (scr_top == vt->topterm)
  525.         scr_top = 0;
  526.  
  527.     D( printf("vtscroll %d lines\n", drow) );
  528.  
  529.     if (vt->lazy && dcol == 0 && r1 == scr_top && r2 == vt->scr_bot &&
  530.         c1 == 0 && c2 == vt->cols) {
  531.         if (drow * vt->toscroll < 0)
  532.             vtsync(vt);
  533.         vt->toscroll += drow;
  534.     }
  535.     else {
  536.         if (vt->toscroll != 0 && r1 < vt->scr_bot && r2 > scr_top)
  537.             vtsync(vt); /* Execute leftover scrolling first */
  538.  
  539.         /* Convert to STDWIN coordinates */
  540.         c1 *= vt->cwidth;
  541.         c2 *= vt->cwidth;
  542.         dcol *= vt->cwidth;
  543.  
  544.         r1 *= vt->cheight;
  545.         r2 *= vt->cheight;
  546.         drow *= vt->cheight;
  547.  
  548.         VTENDDRAWING(vt);
  549.         wnocaret(vt->win);
  550.         wscroll(vt->win, c1, r1, c2, r2, dcol, drow);
  551.  
  552.         /* Despite what the stdwin document says,
  553.            wscroll doesn't generate wchanges anymore */
  554.         if (vt->lazy) {
  555.             if (drow < 0) {        /* Scrolled upwards    */
  556.                 wchange(vt->win, c1, r2+drow, c2, r2);
  557.                 D( printf("^: wchange(%d, %d, %d, %d)\n",
  558.                         c1, r2+drow, c2, r2) );
  559.             }
  560.             else if (drow > 0) {    /* Scrolled downwards    */
  561.                 wchange(vt->win, c1, r1, c2, r1+drow);
  562.                 D( printf("V: wchange(%d, %d, %d, %d)\n",
  563.                         c1, r1, c2, r1+drow) );
  564.             }
  565.             if (dcol < 0) {        /* Scrolled to the left    */
  566.                 wchange(vt->win, c2+dcol, r1, c2, r2);
  567.                 D( printf("<: wchange(%d, %d, %d, %d)\n",
  568.                         c2+dcol, r1, c2, r2) );
  569.             }
  570.             else if (dcol > 0) {    /* Scrolled to the right */
  571.                 wchange(vt->win, c1, r1, c1+dcol, r2);
  572.                 D( printf(">: wchange(%d, %d, %d, %d)\n",
  573.                         c1, r1, c1+dcol, r2) );
  574.             }
  575.         }
  576.     }
  577. }
  578.  
  579. /* Execute delayed scrolling.
  580.    Don't call from within drawproc: wscroll while drawing is BAD. */
  581.  
  582. void
  583. vtsync(vt)
  584.     VT *vt;
  585. {
  586.     VTENDDRAWING(vt);
  587.     if (vt->toscroll != 0) {
  588.         int scr_top = vt->scr_top;
  589. #if 0
  590.         /* XXX Why not? */
  591.         if (vt->toscroll < 0) vtpanic("vtsync: toscroll < 0");
  592. #endif
  593.         if (scr_top == vt->topterm)
  594.             scr_top = 0;
  595.         D( printf("VtSync [,%d]~[,%d] %d: wscroll\n",
  596.             scr_top, vt->scr_bot, vt->toscroll) );
  597.         wscroll(vt->win,
  598.             0, scr_top * vt->cheight,
  599.             vt->cols * vt->cwidth, vt->scr_bot * vt->cheight,
  600.             0, vt->toscroll * vt->cheight);
  601.  
  602.         D( printf("vtsync: ") );
  603.         /* I could get speedup from remembering
  604.          * min and max columns for the call here
  605.          */
  606.         vtchange(vt, vt->scr_bot + vt->toscroll, 0,
  607.             vt->scr_bot, vt->cols);
  608.         vt->toscroll = 0;
  609.     }
  610.     /* vtsetcursor doesn't do this if vt->lazy: */
  611.     if (vt->lazy) {
  612.         MON_EVENT("vtsync for lazy");
  613.         wsetcaret(vt->win,
  614.             vt->cur_col * vt->cwidth,
  615.             vt->cur_row * vt->cheight);
  616.         vtshow(vt, vt->cur_row,vt->cur_col, vt->cur_row+1,vt->cur_col);
  617.     }
  618. }
  619.  
  620. /* Internal VT interface to winvert.
  621.    Must be called between wbegindrawing and wenddrawing. */
  622.  
  623. void
  624. vtinvert(vt, row1, col1, row2, col2)
  625.     VT *vt;
  626.     int row1, col1, row2, col2;
  627. {
  628.     /* XXX Here was some code */
  629.  
  630.     if (row1 == row2) {
  631.         /* Whole selection within one line */
  632.         winvert(col1 * vt->cwidth, row1 * vt->cheight,
  633.             col2 * vt->cwidth, (row2 + 1) * vt->cheight);
  634.     }
  635.     else {
  636.         /* Invert first line of the selection */
  637.         winvert(col1 * vt->cwidth, row1 * vt->cheight,
  638.             vt->cols * vt->cwidth, (row1 + 1) * vt->cheight);
  639.  
  640.         /* Invert intermediate lines, if any */
  641.         if (row1 + 1 < row2) {
  642.             winvert(0, (row1 + 1) * vt->cheight,
  643.                 vt->cols * vt->cwidth, row2 * vt->cheight);
  644.         }
  645.  
  646.         /* Invert last line */
  647.         winvert(0, row2 * vt->cheight,
  648.             col2 * vt->cwidth, (row2 + 1) * vt->cheight);
  649.     }
  650. }
  651.